home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectInput / DIConfig / flexscrollbar.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-08  |  10.8 KB  |  510 lines

  1. //-----------------------------------------------------------------------------
  2. // File: flexscrollbar.cpp
  3. //
  4. // Desc: Implements CFlexScrollBar (derived from CFlexWnd), a scroll bar
  5. //       control similar to a Windows scroll bar.
  6. //
  7. // Copyright (C) 1999-2001 Microsoft Corporation. All Rights Reserved.
  8. //-----------------------------------------------------------------------------
  9.  
  10. #include "common.hpp"
  11.  
  12.  
  13. CFlexScrollBar::CFlexScrollBar() :
  14.     m_nMin(0),
  15.     m_nMax(0),
  16.     m_nPage(25),
  17.     m_nPos(25),
  18.     m_bVert(TRUE),
  19.     m_hWndNotify(NULL),
  20.     m_bValid(FALSE),
  21.     m_bCapture(FALSE),
  22.     m_bDragging(FALSE),
  23.     m_code(SB_ENDSCROLL),
  24.     m_rgbBk(RGB(0,0,0)),
  25.     m_rgbFill(RGB(0,0,255)),
  26.     m_rgbLine(RGB(0,255,255))
  27. {
  28. }
  29.  
  30. CFlexScrollBar::~CFlexScrollBar()
  31. {
  32. }
  33.  
  34. CFlexScrollBar *CreateFlexScrollBar(FLEXSCROLLBARCREATESTRUCT *pcs)
  35. {
  36.     CFlexScrollBar *psb = new CFlexScrollBar;
  37.     
  38.     if (psb && psb->Create(pcs))
  39.         return psb;
  40.     
  41.     delete psb;
  42.     return NULL;
  43. }
  44.  
  45. BOOL CFlexScrollBar::Create(FLEXSCROLLBARCREATESTRUCT *pcs)
  46. {
  47.     if (this == NULL)
  48.         return FALSE;
  49.  
  50.     if (pcs == NULL)
  51.         return FALSE;
  52.  
  53.     if (pcs->dwSize != sizeof(FLEXSCROLLBARCREATESTRUCT))
  54.         return FALSE;
  55.  
  56.     if (pcs->min > pcs->max)
  57.         return FALSE;
  58.  
  59.     int range = pcs->max - pcs->min;
  60.  
  61.     if (pcs->page > range)
  62.         return FALSE;
  63.  
  64.     m_bVert = ( pcs->dwFlags & FSBF_VERT ) == FSBF_VERT;
  65.  
  66.     SetValues(pcs->min, pcs->max, pcs->page, pcs->pos);
  67.  
  68.     m_hWndNotify = pcs->hWndNotify ? pcs->hWndNotify : pcs->hWndParent;
  69.  
  70.     if (!CFlexWnd::Create(pcs->hWndParent, pcs->rect, pcs->bVisible))
  71.         return FALSE;
  72.  
  73.     Calc();
  74.  
  75.     // TODO:  make sure that creation sends no notifications.
  76.     // all initial notifications should be sent here.
  77.  
  78.     return TRUE;
  79. }
  80.  
  81. int CFlexScrollBar::GetLineAdjust()
  82. {
  83.     return 1;
  84. }
  85.  
  86. int CFlexScrollBar::GetPageAdjust()
  87. {
  88.     return m_nPage > 1 ? m_nPage - 1 : 1;
  89. }
  90.  
  91. void CFlexScrollBar::AdjustPos(int adj, BOOL bForceCalc)
  92. {
  93.     int old = m_nPos;
  94.  
  95.     m_nPos += adj;
  96.  
  97.     if (m_nPos < m_nMin)
  98.         m_nPos = m_nMin;
  99.     if (m_nPos > m_nMax - m_nPage)
  100.         m_nPos = m_nMax - m_nPage;
  101.  
  102.     if (m_nPos == old && !bForceCalc)
  103.         return;
  104.  
  105.     if (Calc())
  106.         Invalidate();
  107. }
  108.  
  109. BOOL CFlexScrollBar::FailCalc(BOOL bOldValid)
  110. {
  111.     m_bValid = FALSE;
  112.     if (bOldValid)
  113.         Invalidate();
  114.     return m_bValid;
  115. }
  116.  
  117. BOOL CFlexScrollBar::Calc()
  118. {
  119.     BOOL bOldValid = m_bValid;
  120. #define FAIL return FailCalc(bOldValid)
  121.  
  122.     if (!m_hWnd)
  123.         FAIL;
  124.  
  125.     SRECT zero;
  126.     m_rectLineUp = zero;
  127.     m_rectPageUp = zero;
  128.     m_rectTrack = zero;
  129.     m_rectThumb = zero;
  130.     m_rectPageDown = zero;
  131.     m_rectLineDown = zero;
  132.  
  133.     SPOINT size = GetClientSize();
  134.  
  135.     int ord = m_bVert ? 1 : 0;
  136.     int nord = m_bVert ? 0 : 1;
  137.     int length = size.a[ord];
  138.     int width = size.a[nord];
  139.     int arrowlen = width;
  140.  
  141.     if (width < 1 || length < 2)
  142.         FAIL;
  143.  
  144.     int tracklen = length - arrowlen * 2;
  145.     int trackofs = arrowlen;
  146.  
  147.     BOOL bOverlappingArrows = tracklen < -1;
  148.     int overlap = !bOverlappingArrows ? 0 : -tracklen;
  149.  
  150.     SRECT up, down, track, thumb, temp;
  151.  
  152.     if (overlap > 1)
  153.     {
  154.         int mid = length / 2;
  155.         up.lr.a[nord] = width;
  156.         up.lr.a[ord] = mid;
  157.         down.ul.a[ord] = mid;
  158.         down.lr.a[ord] = length;
  159.         down.lr.a[nord] = width;
  160.         m_rectLineUp = up;
  161.         m_rectLineDown = down;
  162.         return m_bValid = TRUE;
  163.     }
  164.  
  165.     up.lr.a[nord] = width;
  166.     up.lr.a[ord] = arrowlen;
  167.     down.lr.a[nord] = width;
  168.     down.ul.a[ord] = length - arrowlen;
  169.     down.lr.a[ord] = length;
  170.     m_rectLineUp = up;
  171.     m_rectLineDown = down;
  172.  
  173.     int tmin = up.lr.a[ord];
  174.     int tmax = down.ul.a[ord];
  175.     int trange = tmax - tmin;
  176.     int range = m_nMax - m_nMin;
  177.     assert(trange > 0);
  178.     if (!(range > 0) || !(trange > 0))
  179.         return m_bValid = TRUE;
  180.  
  181.     track.ul.a[ord] = tmin;
  182.     track.lr.a[nord] = width;
  183.     track.lr.a[ord] = tmax;
  184.     m_rectTrack = track;
  185.  
  186.     const int minthumblen = 3;
  187.     int thumblen = MulDiv(m_nPage, trange, range);
  188.     if (thumblen < minthumblen)
  189.         thumblen = minthumblen;
  190.  
  191.     int thumbrange = trange - thumblen /*+ 1*/;
  192.     int pagerange = range - m_nPage;
  193.     if (!(pagerange > 1) || !(thumbrange > 1))
  194.         return m_bValid = TRUE;
  195.     int logpos = m_bDragging ? m_nPreDragPos : m_nPos;
  196.     int thumbpos = MulDiv(logpos - m_nMin, thumbrange, pagerange) + tmin;
  197.     if (m_bDragging)
  198.     {
  199.         SPOINT rp = m_point, rs = m_startpoint;
  200.         int rdelta = rp.a[ord] - rs.a[ord];
  201.         thumbpos += rdelta;
  202.         if (thumbpos < tmin)
  203.             thumbpos = tmin;
  204.         if (thumbpos > tmax - thumblen)
  205.             thumbpos = tmax - thumblen;
  206.         m_nThumbPos = MulDiv(thumbpos - tmin, pagerange, thumbrange) + m_nMin;
  207.         if (m_nThumbPos < m_nMin)
  208.             m_nThumbPos = m_nMin;
  209.         if (m_nThumbPos > m_nMax - m_nPage)
  210.             m_nThumbPos = m_nMax - m_nPage;
  211.     }
  212.  
  213.     thumb.ul.a[ord] = thumbpos;
  214.     thumb.lr.a[nord] = width;
  215.     thumb.lr.a[ord] = thumbpos + thumblen;
  216.     m_rectThumb = thumb;
  217.  
  218.     temp = track;
  219.     temp.lr.a[ord] = thumb.ul.a[ord];
  220.     if (temp.lr.a[ord] > temp.ul.a[ord])
  221.         m_rectPageUp = temp;
  222.  
  223.     temp = track;
  224.     temp.ul.a[ord] = thumb.lr.a[ord];
  225.     if (temp.lr.a[ord] > temp.ul.a[ord])
  226.         m_rectPageDown = temp;
  227.  
  228.     return m_bValid = TRUE;
  229. #undef FAIL
  230. }
  231.  
  232. void CFlexScrollBar::SetValues(int min, int max, int page, int pos)
  233. {
  234.     m_nMin = min < max ? min : max;
  235.     m_nMax = max > min ? max : min;
  236.     m_nPage = page;
  237.     AdjustPos(pos - m_nPos, TRUE);
  238. }
  239.  
  240. static BOOL UseRect(const RECT &rect)
  241. {
  242.     if (rect.left >= rect.right || rect.bottom <= rect.top)
  243.         return FALSE;
  244.     return TRUE;
  245. }
  246.  
  247. static void Rectangle(HDC hDC, RECT rect)
  248. {
  249.     if (!UseRect(rect))
  250.         return;
  251.  
  252.     Rectangle(hDC, rect.left, rect.top, rect.right, rect.bottom);
  253. }
  254.  
  255. void CFlexScrollBar::OnPaint(HDC hDC)
  256. {
  257.     HDC hBDC = NULL, hODC = NULL;
  258.     CBitmap *pbm = NULL;
  259.  
  260.     if (!InRenderMode())
  261.     {
  262.         hODC = hDC;
  263.         pbm = CBitmap::Create(GetClientSize(), RGB(0,0,0), hDC);
  264.         if (pbm != NULL)
  265.         {
  266.             hBDC = pbm->BeginPaintInto();
  267.             if (hBDC != NULL)
  268.             {
  269.                 hDC = hBDC;
  270.             }
  271.         }
  272.     }
  273.  
  274.     InternalPaint(hDC);
  275.  
  276.     if (!InRenderMode())
  277.     {
  278.         if (pbm != NULL)
  279.         {
  280.             if (hBDC != NULL)
  281.             {
  282.                 pbm->EndPaintInto(hBDC);
  283.                 pbm->Draw(hODC);
  284.             }
  285.             delete pbm;
  286.         }
  287.     }
  288. }
  289.  
  290. void CFlexScrollBar::InternalPaint(HDC hDC)
  291. {
  292.     HGDIOBJ hPen, hOldPen, hBrush, hOldBrush;
  293.     hPen = (HGDIOBJ)CreatePen(PS_SOLID, 1, m_rgbBk);
  294.     if (hPen != NULL)
  295.     {
  296.         hOldPen = SelectObject(hDC, hPen),
  297.         hOldBrush = SelectObject(hDC, GetStockObject(BLACK_BRUSH));
  298.  
  299.         Rectangle(hDC, m_rectPageUp);
  300.         Rectangle(hDC, m_rectPageDown);
  301.         Rectangle(hDC, m_rectLineUp);
  302.         Rectangle(hDC, m_rectLineDown);
  303.  
  304.         SelectObject(hDC, hOldPen);
  305.         DeleteObject(hPen);
  306.  
  307.         hBrush = (HGDIOBJ)CreateSolidBrush(m_rgbFill);
  308.         if (hBrush != NULL)
  309.         {
  310.             SelectObject(hDC, (HGDIOBJ)hBrush);
  311.  
  312.             hPen = (HGDIOBJ)CreatePen(PS_SOLID, 1, m_rgbFill);
  313.             if (hPen != NULL)
  314.             {
  315.                 SelectObject(hDC, hPen);
  316.  
  317.                 Rectangle(hDC, m_rectThumb);
  318.  
  319.                 SelectObject(hDC, hOldPen);
  320.                 DeleteObject(hPen);
  321.             }
  322.  
  323.             hPen = (HGDIOBJ)CreatePen(PS_SOLID, 1, m_rgbLine);
  324.             if (hPen != NULL)
  325.             {
  326.                 SelectObject(hDC, hPen);
  327.  
  328.                 // draw the two arrows for this scrollbar
  329.                 for (int i = 0; i < 2; i++)
  330.                     DrawArrow(hDC, i ? m_rectLineUp : m_rectLineDown, m_bVert, i);
  331.  
  332.     #if 0
  333.                 // draw the two arrows for this scrollbar
  334.                 for (int i = 0; i < 2; i++)
  335.                 {
  336.                     const RECT &rect = i == 0 ? m_rectLineUp : m_rectLineDown;
  337.                     SRECT srect = rect;
  338.                     srect.right--;
  339.                     srect.bottom--;
  340.                     int ord = m_bVert ? 1 : 0;
  341.                     int nord = m_bVert ? 0 : 1;
  342.                     SPOINT p(i ? srect.lr : srect.ul), b(i ? srect.ul : srect.lr);
  343.                     b.a[ord] += 2 * i - 1;
  344.                     SPOINT t = p;
  345.                     t.a[nord] = (p.a[nord] + b.a[nord]) / 2;
  346.                     SPOINT u;
  347.                     u.a[ord] = b.a[ord];
  348.                     u.a[nord] = p.a[nord];
  349.                     POINT poly[] = { {t.x, t.y}, {u.x, u.y}, {b.x, b.y} };
  350.                     Polygon(hDC, poly, 3);
  351.                 }
  352.     #endif
  353.  
  354.                 SelectObject(hDC, hOldPen);
  355.                 DeleteObject(hPen);
  356.             }
  357.         
  358.             SelectObject(hDC, hOldBrush);
  359.             DeleteObject(hBrush);
  360.         }
  361.     }
  362. }
  363.  
  364. BOOL InRect(const RECT &rect, POINT point)
  365. {
  366.     return UseRect(rect) && PtInRect(&rect, point);
  367. }
  368.  
  369. LRESULT CFlexScrollBar::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  370. {
  371.     switch (msg)
  372.     {
  373.         case WM_SIZE:
  374.             Calc();
  375.             Invalidate();
  376.             return 0;
  377.  
  378.         // make sure flexwnd doesn't do ANYTHING with our mouse messages
  379.         case WM_MOUSEMOVE:
  380.         case WM_LBUTTONUP:
  381.         case WM_LBUTTONDOWN:
  382.         case WM_RBUTTONUP:
  383.         case WM_RBUTTONDOWN:
  384.         case WM_LBUTTONDBLCLK:
  385.         case WM_RBUTTONDBLCLK:
  386.         {
  387.             POINT point = {int(signed short(LOWORD(lParam))), int(signed short(HIWORD(lParam)))};
  388.             m_point = point;
  389.             m_code = HitTest(point);
  390.         }
  391.         case WM_TIMER:
  392.         case WM_CAPTURECHANGED:
  393.             break;
  394.         default:
  395.             return CFlexWnd::WndProc(hWnd, msg, wParam, lParam);
  396.     }
  397.  
  398.     switch (msg)
  399.     {
  400.         case WM_LBUTTONDOWN:
  401.         case WM_LBUTTONDBLCLK:
  402.             if (m_code == SB_ENDSCROLL)
  403.                 goto endscroll;
  404.             if (m_code == SB_THUMBTRACK)
  405.                 m_bDragging = TRUE;
  406.             else
  407.                 SetTimer(m_hWnd, 1, 500, NULL);
  408.             m_startcode = m_code;
  409.             m_startpoint = m_point;
  410.             m_nPreDragPos = m_nPos;
  411.             m_bCapture = TRUE;
  412.             SetCapture();
  413.             if (!m_bDragging)
  414.                 Notify(m_code);
  415.             break;
  416.  
  417.         case WM_LBUTTONUP:
  418.         case WM_MOUSEMOVE:
  419.             if (!m_bDragging)
  420.                 break;
  421.             if (Calc())
  422.             {
  423.                 Invalidate();
  424.                 // Force repaint the updated scrollbar position.  If we don't do this,
  425.                 // the WM_PAINT message will be pre-empted by the WM_FLEXVSCROLL messages.
  426.                 // Sometimes this happens during the entire duration of draggin the scroll
  427.                 // bar.  The result is that the scroll bar does not get updated when
  428.                 // dragging.
  429.                 SendMessage(m_hWnd, WM_PAINT, 0, 0);
  430.             }
  431.             Notify(m_startcode);
  432.             break;
  433.  
  434.         case WM_TIMER:
  435.             if (m_bCapture) switch (wParam)
  436.             {
  437.                 case 1:
  438.                     KillTimer(m_hWnd, 1);
  439.                     SetTimer(m_hWnd, 2, 50, NULL);
  440.                 case 2:
  441.                     if (m_bDragging)
  442.                         break;
  443.                     if (m_code == m_startcode)
  444.                         Notify(m_code);
  445.                     break;
  446.             }
  447.             break;
  448.     }
  449.  
  450.     switch (msg)
  451.     {
  452.         case WM_LBUTTONUP:
  453.         case WM_CAPTURECHANGED:
  454.         endscroll:
  455.             if (m_bCapture)
  456.             {
  457.                 m_bCapture = FALSE;
  458.                 KillTimer(m_hWnd, 1);
  459.                 KillTimer(m_hWnd, 2);
  460.                 ReleaseCapture();
  461.                 if (m_bDragging)
  462.                     Notify(SB_THUMBPOSITION);
  463.                 BOOL bWasDragging = m_bDragging;
  464.                 m_bDragging = FALSE;
  465.                 if (bWasDragging)
  466.                 {
  467.                     if (Calc())
  468.                         Invalidate();
  469.                 }
  470.                 Notify(SB_ENDSCROLL);
  471.             }
  472.             break;
  473.     }
  474.  
  475.     return 0;
  476. }
  477.  
  478. void CFlexScrollBar::Notify(int code)
  479. {
  480.     if (!m_hWndNotify)
  481.         return;
  482.  
  483.     SendMessage(m_hWndNotify, m_bVert ? WM_FLEXVSCROLL : WM_FLEXHSCROLL,
  484.         (WPARAM)code, (LPARAM)(LPVOID)this);
  485. }
  486.  
  487. int CFlexScrollBar::HitTest(POINT point)
  488. {
  489.     if (InRect(m_rectLineUp, point))
  490.         return SB_LINEUP;
  491.     else if (InRect(m_rectLineDown, point))
  492.         return SB_LINEDOWN;
  493.     else if (InRect(m_rectThumb, point))
  494.         return SB_THUMBTRACK;
  495.     else if (InRect(m_rectPageUp, point))
  496.         return SB_PAGEUP;
  497.     else if (InRect(m_rectPageDown, point))
  498.         return SB_PAGEDOWN;
  499.     else
  500.         return SB_ENDSCROLL;
  501. }
  502.  
  503. void CFlexScrollBar::SetColors(COLORREF bk, COLORREF fill, COLORREF line)
  504. {
  505.     m_rgbBk = bk;
  506.     m_rgbFill = fill;
  507.     m_rgbLine = line;
  508.     Invalidate();
  509. }
  510.